package controller;


import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.swing.AbstractAction;

import javax.swing.JComboBox;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTable;

import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import model.AppModel;
import model.Email;
import model.Folder;
import model.ModelException;
import view.AppView;

/**
 * Handles the events and actions in the email Listing pane of the application
 * @author MUSAB
 *
 * @version $Revision: 1.0 $
 */
public class ListingController {

	// Application model, view and main contrlller
	private AppModel model;
	private AppView view;
	private AppController appController;
	
	/**
	 * Constructor takes the view and the model
	 * @param model
	 * @param view
	 * @param appController 
	 */
	public ListingController(AppModel model, AppView view, AppController appController) {
		this.model = model;
		this.view = view;
		this.appController = appController;
		assignHandlersToEvents();
		assignHotkeys();
	}

	private void assignHotkeys() {
		
		view.getListing().getMoveBtn().setMnemonic(KeyEvent.VK_M);
		view.getListing().getDeleteBtn().setMnemonic(KeyEvent.VK_D);
		
	}

	/**
	 * Assigns event handlers to its the listing view
	 */
	private void assignHandlersToEvents() {
		
		// Move button click
		view.getListing().getMoveBtn().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if (!model.getCurrentFolderName().equalsIgnoreCase("Sent") && 
						!model.getCurrentFolderName().equalsIgnoreCase("Drafts") && 
						!model.getCurrentFolderName().equalsIgnoreCase("Outbox") ){
					actionMoveToFolder();
				} else {
					JOptionPane.showMessageDialog(null, "You can not move emails out of this folder manually", "Warning", JOptionPane.INFORMATION_MESSAGE);
				}
				
				
				if (!model.getCurrentFolderName().equalsIgnoreCase("Sent") && 
						!model.getCurrentFolderName().equalsIgnoreCase("Drafts") && 
						!model.getCurrentFolderName().equalsIgnoreCase("Outbox") ){
					actionMoveToFolder();
				} else {
					JOptionPane.showMessageDialog(null, "You can not move emails out of this folder manually", "Warning", JOptionPane.INFORMATION_MESSAGE);
				}
				
				
			}
		});
		
		// Search button click
		view.getListing().getSearchBtn().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				actionSearch();
			}
		});
		
		// Delete button click
		view.getListing().getDeleteBtn().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				actionDeleteEmail();
			}
		});
		
		// Right click on any row in the emails table
		view.getListing().getEmailsTable().addMouseListener(new MouseAdapter(){
			@Override
			public void mousePressed( MouseEvent e ){
				if ( SwingUtilities.isRightMouseButton(e)){
					actionShowRightClickMenu(e);
				}
				
			}
			@Override
			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 2) {
					if (model.getCurrentFolderName().equalsIgnoreCase("Drafts")){
						actionEditEmail();
					}
				}
			}
		});
		
		// Email selection detection
		view.getListing().getEmailsTable().getSelectionModel().addListSelectionListener(new ListSelectionListener() {
			@Override
			public void valueChanged(ListSelectionEvent e) {
				if (e.getValueIsAdjusting() == false){
					actionEmailSelectionChanged();
				}
			}
		});
		
	}
	
	/**
	 * Creates the search view
	 */
	protected void actionSearch() {
		
		new SearchController(model);
		
	}

	/**
	 * fired when email selection in the list has changed
	 */
	protected void actionEmailSelectionChanged() {
		Email firstSelectedEmail = getFirstSelectedEmail();
		if (firstSelectedEmail != null){
			previewEmail(firstSelectedEmail);
		}
	}
	
	/**
	 * Returns the first selected email or null
	
	 * @return The first email that was selected */
	private Email getFirstSelectedEmail(){
		int[] selectedRows = view.getListing().getEmailsTable().getSelectedRows();
		if (selectedRows.length > 0){
			int firstEmailIndex = selectedRows[0];
			int currentFolderId = model.getCurrentFolderId();
			List <Email> emails = model.getUser().getFolder(currentFolderId).getEmails();
			if (firstEmailIndex < emails.size()){
				return emails.get(firstEmailIndex);
			}
		}
		return null;
	}
	
	
	/**
	 * Preview a given email object in the preview pane
	 * @param email Email
	 */
	private void previewEmail(Email email){
		view.getPreview().clear();
		view.getPreview().setTo(email.getTo());
		view.getPreview().setFrom(email.getFrom());
		view.getPreview().setSubject(email.getSubject());
		view.getPreview().setBodyText(email.getBody());
		view.getPreview().setDate(email.getTimestamp());
	}
	

	/**
	 * Show right click menu when a row is right clicked on the table
	
	 * @param e MouseEvent
	 */
	protected void actionShowRightClickMenu(MouseEvent e) {
		
		// Selecting the currently right clicked row in the table
		JTable emailsTable = view.getListing().getEmailsTable();
		Point p = e.getPoint();
		int rowNumber = emailsTable.rowAtPoint( p );
		ListSelectionModel selectionModel = emailsTable.getSelectionModel();
		selectionModel.setSelectionInterval( rowNumber, rowNumber );

		// Creating the popup menu with options
		JPopupMenu popup = new JPopupMenu("Email options");
		JMenuItem editItem = new JMenuItem(new AbstractAction("Edit") {
		    public void actionPerformed(ActionEvent e) {
		        actionEditEmail();
		    }
		});
		JMenuItem moveItem = new JMenuItem(new AbstractAction("Move") {
		    public void actionPerformed(ActionEvent e) {
		        actionMoveToFolder();
		    }
		});
		JMenuItem deleteItem = new JMenuItem(new AbstractAction("Delete") {
		    public void actionPerformed(ActionEvent e) {
		        actionDeleteEmail();
		    }
		});
		
		// Edit action for drafts folder if only one item is selected
		if (model.getCurrentFolderName().equalsIgnoreCase("Drafts")){
			popup.add(editItem);
		}
		
		
		if (!model.getCurrentFolderName().equalsIgnoreCase("Drafts") &&
				!model.getCurrentFolderName().equalsIgnoreCase("Sent") &&
				!model.getCurrentFolderName().equalsIgnoreCase("Outbox")){
			popup.add(moveItem);
		}
		
		if (!model.getCurrentFolderName().equalsIgnoreCase("Drafts") &&
				!model.getCurrentFolderName().equalsIgnoreCase("Sent") &&
				!model.getCurrentFolderName().equalsIgnoreCase("Outbox")){
			popup.add(moveItem);
		}
		popup.add(deleteItem);
		popup.show(e.getComponent(), e.getX(), e.getY());
	}

	/**
	 * Opens up the compose new email window with the email already selected
	 */
	protected void actionEditEmail() {
		Email firstSelectedEmail = getFirstSelectedEmail();
		if (firstSelectedEmail != null){
			new ComposeMailController(firstSelectedEmail, model, appController);
		}
		
	}
	
	

	/**
	 * Delete selected emails
	
	 */
	protected void actionDeleteEmail() {
		
		int[] selectedRows = view.getListing().getEmailsTable().getSelectedRows();
		
		if (selectedRows.length > 0){
			
			int option = JOptionPane.showConfirmDialog (null, "Are you sure you want to delete the selected emails?");
			if (option == JOptionPane.YES_OPTION ) {
				
				// Loop through and delete the emails
				
				Set<Integer> emailIdsToDelete;
				emailIdsToDelete = new HashSet<Integer>();
				
				// If at least one email was selected
				if (selectedRows.length > 0){
					
					// Collect all ids to be deleted
					for (int index : view.getListing().getEmailsTable().getSelectedRows()){
						emailIdsToDelete.add( model.getUser().getFolder(model.getCurrentFolderId()).getEmails().get(index).getId() );
					}
					
					// Now delete them
					try {
						model.getUser().getFolder(model.getCurrentFolderId()).deleteEmails(emailIdsToDelete);
					} catch (ModelException e) {
						JOptionPane.showMessageDialog(null, "Some emails could not be deleted", "Warning", JOptionPane.INFORMATION_MESSAGE);
					}
					
					appController.getNavigationController().refreshNavigationFolders(model.getCurrentFolderName());
				}
				
			}
		}
		
		
	}
	
	
	/**
	 * Refreshes all the list of emails
	
	 */
	protected void refreshListingView(){
		
		// Set currently selected folder
		
		// Clear the listing view
		view.getListing().clear();
		
		// Get currently selected folder index
		int i = view.getNavigation().getFoldersList().getSelectedIndex();
		
		// If root was selected, don't do anything
		if (i == 0){
			view.getListing().setFolderName("Root");
			model.setCurrentFolderId(0);
			return;
		}
		
		// Get selected folder and its emails
		int fId = view.getNavigation().getFolderIdAt(i);
		model.setCurrentFolderId(fId);
		Folder selectedFolder = model.getUser().getFolder(fId);
		List<Email> selectedFolderEmails = selectedFolder.getEmails();
		
		// Getting the listing model
		DefaultTableModel emailsTableModel = view.getListing().getEmails();
		
		// Set the folder name
		view.getListing().setFolderName(selectedFolder.getName() + ": " + selectedFolderEmails.size() + " emails");
		
		// Now entering each email in this folder into the table model
		int count = 1;
		for (Email email : selectedFolderEmails){
			Object[] row = {
					count,
					email.getTo(),
					email.getFrom(),
					String.valueOf(email.getTimestamp()),
					email.getSubject(),
					email.isRead(),
					email.getId(),
					email.getFolderId()
			};
			emailsTableModel.addRow(row);
			count++;
		}
		
		// Emptying the preview window
		view.getPreview().clear();

	}


	
	/**
	 * Move to folder popup
	
	 */
	private void actionMoveToFolder(){

		int[] selectedRows = view.getListing().getEmailsTable().getSelectedRows();
		
		if (selectedRows.length == 0){
			return;
		}
		
		// Creating folder structure
		List<String> folders = new ArrayList<String>();
		folders.add("--- Select folder ---");
		for(Folder f : model.getUser().getFolders()){
			if (f.getName().trim().equalsIgnoreCase("Drafts") || 
					f.getName().trim().equalsIgnoreCase("Outbox") || 
					f.getName().trim().equalsIgnoreCase("Sent") || 
					f.getName().trim().equalsIgnoreCase(model.getCurrentFolderName())) {
				continue;
			}
			String indent = "";
			int level = model.getUser().getFolderLevel(f.getId());
			for (int i = level ; i < level; i++){
				indent = indent + "     ";
			}
			folders.add(indent + f.getName().trim());
		}
		JComboBox foldersComboBox = new JComboBox(folders.toArray());
		JOptionPane.showMessageDialog(
		  null,
		  foldersComboBox,
		  "Move to folder",
		  JOptionPane.PLAIN_MESSAGE);
		
		// If user did select a valid folder then move
		if (foldersComboBox.getSelectedItem() != null && foldersComboBox.getSelectedIndex() != 0){
			
			// Get the name of the folder selected
			String destinitionFolderName = foldersComboBox.getSelectedItem().toString().trim();
			Folder destinitionFolder = model.getUser().getFolder(destinitionFolderName);

			// Loop through and delete the emails
			Set<Integer> emailIdsToMove = new HashSet<Integer>();
				
			// Collect all ids to be deleted
			for (int index : view.getListing().getEmailsTable().getSelectedRows()){
				emailIdsToMove.add( model.getUser().getFolder(model.getCurrentFolderId()).getEmails().get(index).getId() );
			}
			
			// Now move them
			try {
				model.getUser().getFolder(model.getCurrentFolderId()).moveEmails(emailIdsToMove, destinitionFolder);
			} catch (ModelException e) {
				JOptionPane.showMessageDialog(null, "Some emails could not be deleted", "Warning", JOptionPane.INFORMATION_MESSAGE);
			}
			
			appController.getNavigationController().refreshNavigationFolders(model.getCurrentFolderName());
		}
		
	}
}
